package cc.owoo.godpen.network.console;

import cc.owoo.godpen.util.N;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 控制台工具（线程安全）
 * Created by nimensei
 * 2022-03-25 下午 01:48
 **/
public class Console {
    private final Object lock = new Object();// 线程锁
    private PrintStream print;// 字符输出流
    private OutputStream out;// 输出流
    private Progress progress;// 当前进度
    private String fixedContent;// 固定文本

    public Console() {
        this(System.out);
    }

    public Console(String ip, int port) {
        try {
            Socket socket = new Socket(ip, port);
            out = socket.getOutputStream();
        } catch (IOException ignored) {
        }
    }

    public Console(OutputStream out) {
        this.out = out;
    }

    public Console(PrintStream out) {
        this.print = out;
    }

    /**
     * 输出
     *
     * @param s 输出的文本
     */
    public void print(String s) {
        if (out != null) {
            try {
                synchronized (this) {
                    out.write(s.getBytes(StandardCharsets.UTF_8));
                }
            } catch (IOException ignored) {
            }
        }
        if (print != null)
            print.print(s);
    }

    /**
     * 输出并换行
     *
     * @param s 输出的文本
     */
    public void println(String s) {
        if (out != null)
            try {
                synchronized (this) {
                    out.write((s + "\n").getBytes(StandardCharsets.UTF_8));
                }
            } catch (IOException ignored) {
            }
        if (print != null)
            print.println(s);
    }

    /**
     * 输出一个换行符
     */
    public void println() {
        if (out != null)
            try {
                synchronized (this) {
                    out.write("\n".getBytes(StandardCharsets.UTF_8));
                }
            } catch (IOException ignored) {
            }
        if (print != null)
            print.println();
    }

    /**
     * 更改或显示固定文本
     *
     * @param string 需要显示的文本
     */
    public void fixed(String string) {
        if (string == null)
            return;
        synchronized (lock) {
            int max = 0;
            if (fixedContent != null) {
                max = fixedContent.length() - string.length();
                printBackspace();
            }
            string += cc.owoo.godpen.util.N.pow(" ", max);
            print(string);
            fixedContent = string;
        }
    }

    /**
     * 打印
     *
     * @param string 需要打印的内容
     */
    public void log(String string) {
        synchronized (lock) {
            String temp = fixedContent;
            fixed(string);
            println();
            fixedContent = null;
            if (temp != null)
                fixed(temp);
        }
    }

    /**
     * 显示进度
     *
     * @param name     进度名称
     * @param progress 进度值（0~1）
     */
    public void progress(String name, double progress) {
        progress(name, progress, null);
    }

    /**
     * 显示进度
     *
     * @param name     进度名称
     * @param progress 进度值（0~1）
     * @param postfix  后缀
     */
    public void progress(String name, double progress, String postfix) {
        progress(new Progress(name, progress, postfix));
    }

    /**
     * 显示进度
     *
     * @param progress 进度
     */
    public void progress(Progress progress) {
        if (progress == null)
            return;
        synchronized (lock) {
            if (this.progress != null && this.progress.equals(progress))
                return;
            this.progress = progress;
        }
        StringBuilder string = new StringBuilder();
        if (progress.name != null)
            string.append(progress.name);
        string.append(progress.index).append("% ");
        int block = progress.index >> 1;
        char PROGRESS_FULL = '█';
        char PROGRESS_BLANK = '|';
        for (int i = 0; i < 50; i++)
            string.append(i < block ? PROGRESS_FULL : PROGRESS_BLANK);
        if (progress.postfix != null)
            string.append(' ').append(progress.postfix);
        fixed(string.toString());
    }

    /**
     * 清空当前固定文本
     */
    public void clearFixed() {
        synchronized (lock) {
            if (fixedContent == null)
                return;
            fixed(cc.owoo.godpen.util.N.pow(" ", fixedContent.length()));
            printBackspace();
            fixedContent = null;
            progress = null;
        }
    }

    /**
     * 打印\b清空当前固定文本
     */
    public void printBackspace() {
        print(N.pow("\b", fixedContent.length()));
    }

    /**
     * 清除所有文本
     */
    public void clear() {
        if (print != System.out)
            return;
        try {
            new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
        } catch (Exception ignored) {
        }
    }

    /**
     * 关闭连接
     */
    public void close() {
        clearFixed();
        if (print == null || print == System.out)
            return;
        print.close();
    }

    /**
     * 进度
     */
    public static class Progress {
        public String name;
        public int index;
        public String postfix;

        public Progress() {
            this(null, 0, null);
        }

        public Progress(String name, double progress) {
            this(name, progress, null);
        }

        public Progress(String name, double progress, String postfix) {
            this.name = name;
            this.index = (int) Math.round(progress * 100d);
            this.postfix = postfix;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Progress progress = (Progress) o;
            return index == progress.index && Objects.equals(postfix, progress.postfix) && Objects.equals(name, progress.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, index, postfix);
        }
    }
}
